#include "cmsis_os.h"
#include "tos_sem.h"
#include "tos_mutex.h"
#include <unistd.h>

#define PRODUCER_STK_SIZE		512
void producer(void *arg);

#define CONSUMER_STK_SIZE	512
void consumer(void *arg);

#define BUFFER_SIZE 5
#define NUM_PRODUCERS 5
#define NUM_CONSUMERS 5

int buffer[BUFFER_SIZE]; //用数组作为缓冲区
int in = 0; //生产者当前位置
int out = 0; //消费者当前位置

k_sem_t empty; //缓冲区的空闲空间
k_sem_t full; //缓冲区的已用空间
struct k_mutex_st mutex; //互斥锁，保护对缓冲区的访问

void producer(void *arg)
{
    int id = *(int*)arg;
    int item;
    while (1) {
        item = rand() % 100; // 生成随机数作为生产的项目
        tos_sem_pend(&empty, TOS_TIME_FOREVER);// 等待空闲空间
        tos_mutex_pend(&mutex); //进入临界区
        
        buffer[in] = item;
        in = (in + 1) % BUFFER_SIZE;
        printf("Producer %d produced: %d\n",id, item);

        tos_mutex_post(&mutex); // 离开临界区
        tos_sem_post(&full); // 增加已用空间的信号量

        tos_sleep_ms(1100); //模拟生产时间

        // /sleep(1);
    }
}

void consumer(void *arg)
{
    int id = *(int*)arg;
    int item;
    while (1) {

        tos_sem_pend(&full, TOS_TIME_FOREVER); // 等待已用空间
        tos_mutex_pend(&mutex); // 进入临界区

        item = buffer[out];
        out = (out + 1) % BUFFER_SIZE;
        printf("Consumer %d consumed: %d\n",id, item);
        tos_mutex_post(&mutex); // 离开临界区
        tos_sem_post(&empty); // 增加空闲空间的信号量
        tos_sleep_ms(1000);//模拟消费时间
    }
}


int main(void)
{
    osThreadDef_t producers[NUM_PRODUCERS], consumers[NUM_CONSUMERS];
    int producer_ids[NUM_PRODUCERS], consumer_ids[NUM_CONSUMERS];
    k_task_t producer_tasks[NUM_PRODUCERS], consumer_tasks[NUM_CONSUMERS];
    k_stack_t producer_stacks[NUM_PRODUCERS][PRODUCER_STK_SIZE], consumer_stacks[NUM_CONSUMERS][CONSUMER_STK_SIZE];
    int index;
    tos_sem_create_max(&empty, BUFFER_SIZE, BUFFER_SIZE); //初始信号量
    tos_sem_create_max(&full, 0, BUFFER_SIZE); //
    tos_mutex_create(&mutex); //初始化互斥锁

    osKernelInitialize(); //TOS Tiny kernel initialize

    for(index = 0; index < NUM_PRODUCERS; index++){
        producers[index].name = (char*)malloc(K_TASK_NAME_LEN_MAX);
        sprintf(producers[index].name, "producer_%d", index);

        producers[index].pthread   = (os_pthread)producer;
        producers[index].tpriority = osPriorityNormal;
        producers[index].instances = NUM_PRODUCERS;
        producers[index].stackbase = producer_stacks[index]; 
        producers[index].stacksize = PRODUCER_STK_SIZE;
        producers[index].timeslice = 0u;
        producers[index].task      = &producer_tasks[index];

        producer_ids[index] = index;

        osThreadCreate(&producers[index], &producer_ids[index]);
    }

    for(index = 0; index < NUM_PRODUCERS; index++){
        consumers[index].name = (char*)malloc(K_TASK_NAME_LEN_MAX);
        sprintf(producers[index].name, "consumer_%d", index);
        consumers[index].pthread   = (os_pthread)consumer;
        consumers[index].tpriority = osPriorityNormal;
        consumers[index].instances = NUM_CONSUMERS;
        consumers[index].stackbase = consumer_stacks[index]; 
        consumers[index].stacksize = CONSUMER_STK_SIZE;
        consumers[index].timeslice = 0u;
        consumers[index].task      = &consumer_tasks[index];

        consumer_ids[index] = index;
        osThreadCreate(&consumers[index], &consumer_ids[index]);
    }

    // osThreadCreate(osThread(producer), NULL); // Create task1
    // osThreadCreate(osThread(consumer), NULL); // Create task2  
    osKernelStart(); //Start TOS Tiny

    //退出的时候释放资源
    tos_sem_destroy(&empty); 
    tos_sem_destroy(&full);
    tos_mutex_destroy(&mutex);
}
